package com.cola.custSpeechTranscription.api;

import com.cola.custSpeechTranscription.model.CustShareSession;
import com.cola.custSpeechTranscription.model.ResetResult;
import com.cola.custSpeechTranscription.model.ShareVo;
import com.cola.custSpeechTranscription.model.UserSession;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @BelongsProject: custSpeechTranscription
 * @BelongsPackage: com.cola.custSpeechTranscription.api
 * @Author: jiangkang
 * @CreateTime: 2025-10-30  15:29
 * @Description: TODO
 * @Version: 1.0
 */
@Component
public class CustShareSessionManager {

    private static final Logger log = LoggerFactory.getLogger("LCAP_EXTENSION_LOGGER");

    /**
     * 用户会话存储: userId -> UserSession
     */
    private static final Map<String, UserSession> userSessions = new ConcurrentHashMap<>();

    /**
     * 分享会话存储: shareId -> ShareSession
     */
    private static final Map<String, CustShareSession> shareSessions = new ConcurrentHashMap<>();

    /**
     * WebSocket会话到用户ID的映射: sessionId -> userId
     */
    private static final Map<String, String> sessionToUserMap = new ConcurrentHashMap<>();

    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 创建或获取用户会话（不自动创建分享）
     */
    public UserSession getOrCreateUserSession(String userId, WebSocketSession audioSession) {
        return userSessions.compute(userId, (key, existingSession) -> {
            if (existingSession != null) {
                // 更新音频会话
                existingSession.setAudioSession(audioSession);
                log.info("[更新用户会话] userId={}, 新的audioSessionId={}", userId, audioSession.getId());
                return existingSession;
            } else {
                // 创建新用户会话
                UserSession newSession = new UserSession(userId, audioSession);
                log.info("[创建用户会话] userId={}, audioSessionId={}", userId, audioSession.getId());
                return newSession;
            }
        });
    }

    /**
     * 手动创建分享会话
     */
    public String createShareSession(String userId) {
        UserSession userSession = userSessions.get(userId);
        if (userSession == null) {
            throw new IllegalStateException("用户会话不存在: " + userId);
        }

        // 如果已有分享会话，返回现有分享ID
        if (userSession.getShareSession() != null) {
            return userSession.getShareSession().getShareId();
        }

        String shareId = generateShareId();
        CustShareSession shareSession = new CustShareSession(shareId, userSession);
        shareSessions.put(shareId, shareSession);
        userSession.setShareSession(shareSession);

        log.info("[手动创建分享] userId={}, shareId={}", userId, shareId);
        return shareId;
    }

    /**
     * 处理观看者连接 - 自动加入分享并发送历史数据
     */
    public boolean handleViewerConnection(String shareId, WebSocketSession viewSession) {
        if (shareId == null || shareId.trim().isEmpty()) {
            log.info("[观看者连接] 缺少shareId参数");
            return false;
        }

        CustShareSession shareSession = shareSessions.get(shareId);
        if (shareSession == null) {
            log.info("[观看者连接] 分享会话不存在 shareId={}", shareId);
            return false;
        }

        // 生成观看者ID
        String viewerUserId = "viewer_" + System.currentTimeMillis() + "_" +
                UUID.randomUUID().toString().substring(0, 4);

        // 加入分享会话
        shareSession.addViewSession(viewSession, viewerUserId);
        addSessionToUserMapping(viewSession.getId(), viewerUserId);

        log.info("[自动加入分享] shareId={}, viewerUserId={}, viewSessionId={}",
                shareId, viewerUserId, viewSession.getId());

        // 发送欢迎消息和所有历史记录
        sendWelcomeMessageWithHistory(viewSession, shareSession, viewerUserId);

        return true;
    }

    /**
     * 发送欢迎消息和历史数据给观看者
     */
    private void sendWelcomeMessageWithHistory(WebSocketSession viewSession, CustShareSession shareSession, String viewerUserId) {
        try {
            // 发送连接成功消息
//            JSONObject welcomeMsg = new JSONObject();
//            welcomeMsg.put("type", "viewer_connected");
//            welcomeMsg.put("viewerUserId", viewerUserId);
//            welcomeMsg.put("shareId", shareSession.getShareId());
//            welcomeMsg.put("ownerUserId", shareSession.getOwnerUserSession().getUserId());
//            welcomeMsg.put("message", "已自动加入分享会话");
//            viewSession.sendMessage(new TextMessage(welcomeMsg.toString()));

            // 发送会话信息
//            JSONObject sessionInfo = new JSONObject();
//            sessionInfo.put("type", "session_info");
//            sessionInfo.put("shareId", shareSession.getShareId());
//            sessionInfo.put("ownerUserId", shareSession.getOwnerUserSession().getUserId());
//            sessionInfo.put("createTime", shareSession.getCreateTime());
//            sessionInfo.put("viewerCount", shareSession.getViewerCount());
//            viewSession.sendMessage(new TextMessage(sessionInfo.toString()));

            // 发送所有历史转写记录
            List<String> transcripts = shareSession.getOwnerUserSession().getTranscripts();
            if (!transcripts.isEmpty()) {
//                JSONObject historyInfo = new JSONObject();
//                historyInfo.put("type", "history_start");
//                historyInfo.put("count", transcripts.size());
//                viewSession.sendMessage(new TextMessage(historyInfo.toString()));

                // 逐条发送历史记录
                for (String transcript : transcripts) {
                    viewSession.sendMessage(new TextMessage(transcript));
                }

//                JSONObject historyEnd = new JSONObject();
//                historyEnd.put("type", "history_end");
//                viewSession.sendMessage(new TextMessage(historyEnd.toString()));

                log.info("[发送历史数据] 向观看者 {} 发送了 {} 条历史记录",
                        viewerUserId, transcripts.size());
            } else {
//                JSONObject noHistory = new JSONObject();
//                noHistory.put("type", "no_history");
//                noHistory.put("message", "暂无历史转写记录");
//                viewSession.sendMessage(new TextMessage(noHistory.toString()));
            }

        } catch (IOException e) {
            log.error("[发送欢迎消息和历史数据] 失败 viewerUserId={}", viewerUserId, e);
        }
    }

    /**
     * 音频会话断开时立即清理
     */
    public void cleanupOnAudioSessionClosed(WebSocketSession audioSession) {
        String userId = sessionToUserMap.remove(audioSession.getId());
        if (userId == null) {
            log.info("[音频会话断开清理] 未找到对应的userId, sessionId={}", audioSession.getId());
            return;
        }

        log.info("[音频会话断开清理] 开始清理 userId={}, sessionId={}", userId, audioSession.getId());

        UserSession userSession = userSessions.get(userId);
        if (userSession != null) {
            // 1. 检查当前音频会话是否匹配
            if (audioSession.equals(userSession.getAudioSession())) {
                // 只有匹配时才清理音频会话引用
                userSession.setAudioSession(null);
                log.info("[清理音频会话引用] userId={}", userId);
            } else {
                log.info("[跳过音频会话清理] 会话不匹配，可能是重复清理 userId={}", userId);
            }

            // 2. 如果用户有分享会话，清理分享会话
            CustShareSession shareSession = userSession.getShareSession();
            if (shareSession != null) {
                cleanupShareSession(shareSession);
            }

            // 3. 检查是否完全清理用户会话
            checkAndCleanupUserSession(userId, userSession);
        }else {
            log.info("[用户会话已不存在] userId={}", userId);
        }

        // 4. 清理映射关系
        sessionToUserMap.remove(audioSession.getId());
        log.info("[音频会话断开清理] 完成 userId={}", userId);
    }

    /**
     * 清理会话映射（不清理用户数据）
     */
    public void cleanupSessionMappings(WebSocketSession session) {
        String sessionId = session.getId();
        String userId = sessionToUserMap.remove(sessionId);

        if (userId != null) {
            UserSession userSession = userSessions.get(userId);
            if (userSession != null) {
                // 只清理会话引用，不清理用户数据
                if (session.equals(userSession.getAudioSession())) {
                    userSession.setAudioSession(null);
                    log.info("[清理音频会话映射] userId={}, 保留历史记录 {} 条",
                            userId, userSession.getTranscripts().size());
                }
            }
        }
        log.info("[清理会话映射完成] sessionId={}", sessionId);
    }

    /**
     * 重置用户会话（清除历史数据 + 停止分享）
     */
    public ResetResult resetUserSession(String userId) {
        UserSession userSession = userSessions.get(userId);
        ResetResult result = new ResetResult();

        if (userSession != null) {
            // 1. 清除历史数据
            int historyCount = userSession.getTranscripts().size();
            userSession.clearTranscripts();
            result.setClearedHistoryCount(historyCount);

            // 2. 停止分享会话
            CustShareSession shareSession = userSession.getShareSession();
            if (shareSession != null) {
                String shareId = shareSession.getShareId();
                cleanupShareSession(shareSession);
                result.setStoppedSharing(true);
                result.setShareId(shareId);
                log.info("[重置会话] userId={}, 清除历史记录 {} 条, 停止分享会话: {}",
                        userId, historyCount, shareId);
            } else {
                result.setStoppedSharing(false);
                log.info("[重置会话] userId={}, 清除历史记录 {} 条, 无分享会话",
                        userId, historyCount);
            }
        } else {
            log.info("[重置会话] 用户会话不存在 userId={}", userId);
        }

        return result;
    }

    /**
     * 观看会话断开时立即清理
     */
    public void cleanupOnViewSessionClosed(WebSocketSession viewSession) {
        String viewerUserId = sessionToUserMap.remove(viewSession.getId());
        if (viewerUserId == null) {
            log.warn("[观看会话断开清理] 未找到对应的viewerUserId, sessionId={}", viewSession.getId());
            return;
        }

        log.info("[观看会话断开清理] 开始清理 viewerUserId={}, sessionId={}", viewerUserId, viewSession.getId());

        // 从所有分享会话中移除该观看者
        for (CustShareSession shareSession : shareSessions.values()) {
            shareSession.removeViewSessionByUserId(viewerUserId);

            // 如果分享会话没有观看者了，检查是否需要清理
            if (shareSession.getViewerCount() == 0) {
                checkAndCleanupShareSession(shareSession);
            }
        }

        log.info("[观看会话断开清理] 完成 viewerUserId={}", viewerUserId);
    }

    /**
     * 清理分享会话
     */
    private void cleanupShareSession(CustShareSession shareSession) {
        String shareId = shareSession.getShareId();

        // 1. 通知所有观看者分享已结束
        shareSession.broadcastToViewers(createSessionEndMessage());

        // 2. 关闭所有观看者连接
        shareSession.closeAllViewerSessions();

        // 3. 从分享会话映射中移除
        shareSessions.remove(shareId);

        // 4. 从用户会话中移除分享引用
        UserSession ownerSession = shareSession.getOwnerUserSession();
        if (ownerSession != null) {
            ownerSession.setShareSession(null);
        }

        log.info("[清理分享会话] shareId={}, 观看者数量={}", shareId, shareSession.getViewerCount());
    }

    /**
     * 检查并清理用户会话
     */
    private void checkAndCleanupUserSession(String userId, UserSession userSession) {
        // 如果用户没有活跃连接且没有分享会话，则完全清理
        if (userSession.getAudioSession() == null) {
            userSessions.remove(userId);
            log.info("[完全清理用户会话] userId={}, 历史记录数量={}", userId, userSession.getTranscripts().size());
        } else {
            log.info("[保留用户会话] userId={}, 原因: audioSession={}, shareSession={}",
                    userId,
                    userSession.getAudioSession() != null,
                    userSession.getShareSession() != null);
        }
    }

    /**
     * 检查并清理分享会话
     */
    private void checkAndCleanupShareSession(CustShareSession shareSession) {
        UserSession ownerSession = shareSession.getOwnerUserSession();

        // 如果创建者没有活跃连接，清理分享会话
        if (ownerSession == null || ownerSession.getAudioSession() == null) {
            cleanupShareSession(shareSession);
        }
    }

    /**
     * 创建会话结束消息
     */
    private String createSessionEndMessage() {
        JSONObject message = new JSONObject();
        message.put("type", "session_ended");
        message.put("message", "分享会话已结束");
        message.put("timestamp", System.currentTimeMillis());
        return message.toString();
    }

    /**
     * 添加session到user的映射
     */
    public void addSessionToUserMapping(String sessionId, String userId) {
        sessionToUserMap.put(sessionId, userId);
    }

    /**
     * 移除session到user的映射
     */
    public void removeSessionToUserMapping(String sessionId) {
        sessionToUserMap.remove(sessionId);
    }

    /**
     * 强制清理用户所有会话数据
     */
    public void forceCleanupUser(String userId) {
        log.info("[强制清理用户] userId={}", userId);

        UserSession userSession = userSessions.get(userId);
        if (userSession != null) {
            //  首先清除历史数据
            int historyCount = userSession.getTranscripts().size();
            userSession.clearTranscripts();
            log.info("[清除历史数据] userId={}, 清除了 {} 条记录", userId, historyCount);

            // 清理音频会话
            if (userSession.getAudioSession() != null) {
                try {
                    userSession.getAudioSession().close();
                } catch (IOException e) {
                    log.error("[关闭音频会话] 异常 userId={}", userId, e);
                }
                userSession.setAudioSession(null);
            }

            // 清理分享会话
            CustShareSession shareSession = userSession.getShareSession();
            if (shareSession != null) {
                updateShareStatus("1",null,shareSession.getShareId());
                cleanupShareSession(shareSession);
            }

            // 移除用户会话
            userSessions.remove(userId);
            log.info("[强制移除用户会话] userId={}", userId);
        }else {
            log.info("[用户会话不存在] userId={}", userId);
        }

        // 清理所有相关的session映射
        sessionToUserMap.entrySet().removeIf(entry -> userId.equals(entry.getValue()));
        log.info("[清理session映射] userId={}, 剩余用户会话: {}", userId, userSessions.size());
    }

    public void updateShareStatus(String type,String userId,String shareId){
        //去更新分享状态
//        if ("1".equals(type)){
//            UserSession userSession = getUserSession(userId);
//            CustShareSession shareSession = userSession.getShareSession();
//            shareId = shareSession.getShareId();
//        }

        ShareVo shareVo = new ShareVo();
        shareVo.setType(type);
        shareVo.setSessionId(shareId);
        try {
            String bodyStr = MAPPER.writeValueAsString(shareVo);
            postJson("http://localhost:8080/rest/updateShare", bodyStr, null);
        }catch (Exception e){
            log.error("创建者更新失败，分享id为:{}，错误为：{}",shareId,e);
        }
    }

    /**
     * 通过sessionId获取userId
     */
    public String getUserIdBySessionId(String sessionId) {
        return sessionToUserMap.get(sessionId);
    }

    public void removeAudioSession(WebSocketSession audioSession) {
        String userId = sessionToUserMap.remove(audioSession.getId());
        if (userId != null) {
            UserSession userSession = userSessions.get(userId);
            if (userSession != null) {
                userSession.setAudioSession(null);
                log.info("[移除音频会话] userId={}, audioSessionId={}", userId, audioSession.getId());
            }
        }
    }

    public static String postJson(String url, String jsonBody, Map<String, String> headers) throws IOException {
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(new StringEntity(jsonBody, ContentType.APPLICATION_JSON));

            if (headers != null) {
                headers.forEach(httpPost::addHeader);
            }

            try (CloseableHttpResponse response = client.execute(httpPost)) {
                HttpEntity entity = response.getEntity();
                return entity != null ? EntityUtils.toString(entity, StandardCharsets.UTF_8) : null;
            }
        }
    }

    public void removeViewSession(WebSocketSession viewSession) {
        String viewerUserId = sessionToUserMap.remove(viewSession.getId());
        if (viewerUserId != null) {
            shareSessions.values().forEach(shareSession ->
                    shareSession.removeViewSessionByUserId(viewerUserId));
            log.info("[移除观看会话] viewerUserId={}, viewSessionId={}",
                    viewerUserId, viewSession.getId());
        }
    }

    public void addTranscript(String userId, String message) {
        UserSession userSession = userSessions.get(userId);
        if (userSession != null) {
            userSession.addTranscript(message);

            CustShareSession shareSession = userSession.getShareSession();
            if (shareSession != null) {
                shareSession.broadcastToViewers(message);
            }
        }
    }

    public List<String> getUserHistory(String userId) {
        UserSession userSession = userSessions.get(userId);
        return userSession != null ? userSession.getTranscripts() : Collections.emptyList();
    }

    public UserSession getUserSession(String userId) {
        return userSessions.get(userId);
    }

    public boolean isValidShareId(String shareId) {
        return shareSessions.containsKey(shareId);
    }

    public CustShareSession getShareSession(String shareId) {
        return shareSessions.get(shareId);
    }

    private String generateShareId() {
        return UUID.randomUUID().toString().substring(0, 8).toUpperCase();
    }
}